﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;

namespace SavannaFrame.Classes
{
    public class FramesChangedEventArgs
    {
        private List<Frame> framesList=null;

        private List<Domain> domainList = null;

        public List<Domain> DomainList
        {
            get { return domainList; }
        }

        /// <summary>
        /// Обновленный список фреймов
        /// </summary>
        public List<Frame> FramesList
        {
            get
            {
                return this.framesList;
            }
        }

        public FramesChangedEventArgs(List<Frame> framesList)
        {
            this.framesList = framesList;
        }
    }

    public delegate void FramesChagedEventHandler(object sender, FramesChangedEventArgs args);

    public class KnowLedgeBase
    {
        public static List<Frame> Frames = new List<Frame>();
        public static List<FrameExample> FramesExamples = new List<FrameExample>();
		public static List<Domain> Domains = new List<Domain>();
        public static xmlSerial ser = new xmlSerial();
        public static int MaxFrameId = 0;
        public static int MaxSlotId = 0;

        /// <summary>
        /// Событие изменения списка фреймов (добавление/удаление фрейма, загрузка другой БЗ, изменение связей "is a" между фреймами).
        /// На данный момент НЕ вызывается при добавлении/удалении связи "subframe".
        /// </summary>
        public event FramesChagedEventHandler FramesChangedEvent; 

        public KnowLedgeBase()
        {
            Frames = new List<Frame>();
            ser.Domains = Domains;
            ser.Frames = Frames;
            MaxFrameId = 0;
            MaxSlotId = 0;
        }

        public void Save(string FStream)
        {
            if (Frames.Count > 0)
            {
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(xmlSerial));
                FileStream fs = new FileStream(FStream, FileMode.Create);
                xmlSerializer.Serialize(fs, ser);
                fs.Close();
                MessageBox.Show("Правила успешно сохранены!", "Информация");
            }
            else
            {
                MessageBox.Show("В базе знаний нет правил!", "Информация");
            }
        }

        public void Load(string fStream)
        {
            try
            {
                XmlSerializer xmlSerializer = new XmlSerializer(typeof(xmlSerial));
                StreamReader textReader = new StreamReader(fStream);
                ser = (xmlSerial)xmlSerializer.Deserialize(textReader);
                textReader.Close();

                foreach (Frame frame in ser.Frames)
                {
                    if (frame.FrameId > MaxFrameId)
                        MaxFrameId = frame.FrameId;
                }
                MaxFrameId++;


            }
            catch
            {
                MessageBox.Show("Невозможно загрузить из файла!!!", "Ошибка");
            }
            finally
            {
                Frames = ser.Frames;
                Domains = ser.Domains;
            }
            if (this.FramesChangedEvent != null)
                this.FramesChangedEvent(this, new FramesChangedEventArgs(this.FrameList()));
        }

        /// <summary>
        /// Возвращает список типов слотов
        /// </summary>
        public List<string> SlotTypes()
        {
            //List<string> types = new List<string> { "Boolean", "Integer", "String", "Frame", "Productions", "Procedure", "FramePrototype" };
            List<string> types = new List<string> { "Boolean", "Frame", "FramePrototype", "Integer", "Procedure", "Production", "String" };
            return types;
        }

        public List<string> InheritType()
        {
            List<string> types = new List<string> { "Override", "Same", "Unique", "Range"};
            return types;
        }

        //public List<string> DefaultValue(int frameId)
        //{
        //    var slot = new Slot();
        //    slot = FrameList().Find(f => f.FrameId == frameId).GetSlotDefaultValue();
        //}

        public List<string> DomainList()
        {
            List<string> lst = new List<string>();
            foreach (Domain domain in Domains)
            {
                lst.Add(domain.Name);
            }
            return lst;
        }
        public int GetMaxNodeId(int i)
        {
            return MaxFrameId++;
        }

        public int GetMaxNodeId()
        {
            return MaxFrameId;
        }

        public int GetMaxSlotId(int i)
        {
            return MaxSlotId++;
        }

        public int GetMaxSlotId()
        {
            return MaxSlotId;
        }

        public bool AddFrame(Frame frame)
        {
            if (frame != null)
            {
                Frames.Add(frame);
                if (this.FramesChangedEvent != null)
                    this.FramesChangedEvent(this, new FramesChangedEventArgs(this.FrameList()));
                return true;
            }
            return false;
        }

        public bool DeleteFrame(string name)
        {
            if (name != String.Empty)
            {
                int index = Frames.FindIndex(f => f.FrameName == name);
                Frames.RemoveAt(index);
                if (this.FramesChangedEvent != null)
                    this.FramesChangedEvent(this, new FramesChangedEventArgs(this.FrameList()));
                return true;
            }
            return false;
        }

        public bool AddIsA(Frame frame)
        {
            // выбираем фрейм, у слота IsA присваиваем 
            Frames.Find(f => f.FrameId == frame.FrameId).IsA = frame.IsA;
            if (this.FramesChangedEvent != null)
                this.FramesChangedEvent(this, new FramesChangedEventArgs(this.FrameList()));
            return true;
        }

        //public List<Slot> EditGridSlots(string framename)
        //{
        //    Frame frm = Frames.Find(f => f.FrameName == framename);
        //    List<Slot> lst = new List<Slot>();
        //    lst.Add(frm.IsA);
        //    lst.Add(frm.Error);
        //}

        public List<Frame> FrameList ()
        {
            return Frames;
        }

        public List<string> strFrmList()
        {
            List<string> list = new List<string>();
            foreach (Frame frame in Frames)
            {
                list.Add(frame.FrameName);
            }
            return list;
        }

        public List<Slot> SlotList(int frameId)
        {
            List<Slot> listSlot = new List<Slot>();
            Frame frm = Frames.Find(f => f.FrameId == frameId);
            Slot slotname = new Slot() { IsSystem = true, SlotId = -1, SlotName = "NAME", SlotDefault = frm.FrameName, SlotType = SlotType.String };
            listSlot.Add(slotname);
            listSlot.Add(frm.IsA);
            listSlot.Add(frm.Error);
            listSlot.AddRange(frm.FrameSlots);
            return listSlot;
        }

        public static Frame getFrameByID(int frameID)
        {
            return Frames.Find(f => f.FrameId == frameID);
        }

        public static Frame getFrameByName(string frameName)
        {
            frameName = frameName.Trim().ToLower();
            return Frames.Find(f => f.FrameNameTrimmed.Length == frameName.Length && f.FrameNameTrimmed == frameName);
        }

public  void AddDomain(Domain dom)
        {
            if (dom != null)
            {
                if (Domains.Find(d => d.Name == dom.Name) != null)
                    MessageBox.Show("Такое имя уже существует", "Ошибка");
                else
                {
                    Domains.Add(dom);
                }
            }
        }

        public  void DelDomain(Domain dom)
        {
            if (dom != null)
            {
                Domains.Remove(dom);
            }
            else
            {
                MessageBox.Show("Нечего удалять");
            }

        }

        public  bool AddDomainValue(string name, string val)
        {
            Domain current = null;
            foreach (Domain domain in Domains)
            {
                if (domain.Name == name)
                {
                    current = domain;
                    break;
                }
            }
            if (current != null && current.DomainValues == null)
                current.DomainValues = new List<DomainValue>();
            else
            {
                if (current != null && (current.DomainValues.Any(dv => dv.ValueName == val) || val == ""))
                    return false;
            }
            if (current != null)
                current.DomainValues.Add(new DomainValue { ValueName = val });
            ClassFactory.isSaved = false;
            return true;
        }

        public Domain GetDomainByName(string name)
        {
            if (name != String.Empty)
                return Domains.Find(d => d.Name == name);
            else
            {
                return null;
            }
        }

        private List<string> lst = new List<string>();
        public List<string> DomainValues(string name)
        {
            lst.Clear();
            Domain dom = new Domain();
            dom = Domains.Find(d => d.Name == name);
            if (dom == null) return null;
            foreach (DomainValue dom_val in dom.DomainValues)
            {
                lst.Add(dom_val.ValueName);
            }
            return lst;
        }

        public void DelDomainValue(string name, string vname)
        {
            Domain dom = Domains.Find(d => d.Name == name);
            if (dom != null)
            {
                DomainValue dv = dom.DomainValues.Find(d => d.ValueName == vname);
                dom.DomainValues.Remove(dv);
            }
        }

        public void AddSlot(Slot slot, int IdFrame)
        {

            if (slot != null)
            {
                Frame frm = Frames.Find(f => f.FrameId == IdFrame);
                Slot slt = frm.FrameSlots.Find(s => s.SlotName == slot.SlotName);
                if (slt != null)
                {
                    slt = slot;
                }
                else
                {
                    frm.FrameSlots.Add(slot);
                }
            }

        }

        public void DelSlot(Slot slot, int IdFrame)
        {
            if (slot != null)
            {
                Frame frm = Frames.Find(f => f.FrameId == IdFrame);
                frm.FrameSlots.Remove(slot);
            }

        }

    }
}
